import { HTMLAttributes, PropType, computed, defineComponent, onBeforeMount, onMounted, ref } from "vue";

export interface AvatarProps extends HTMLAttributes {
    size?: number|'small'|'large'
    icon?: JSX.Element
    src?: string
    shape?: string
    title?: any
    hoverMask?: any
}

export default defineComponent({
    name: 'Avatar',
    props: {
        size: {
            type: [Number, String] as PropType<AvatarProps['size']>,
        },
        icon: {
            type: Object as PropType<AvatarProps['icon']>,
        },
        src: {
            type: String as PropType<AvatarProps['src']>,
        },
        shape: {
            type: String as PropType<AvatarProps['shape']>,
            default: 'circle'
        },
        title: {
            type: [String, Number, Object] as PropType<AvatarProps['title']>,
        },
        hoverMask: {
            type: [String, Object] as PropType<AvatarProps['hoverMask']>,
        },
    },
    emits: ['click', 'mouseEnter', 'mouseLeave'],
    setup (props: AvatarProps, {emit, slots}) {
        const hover = ref(false);
        const classList = computed(() => ({
            'cm-avatar': true,
            [`cm-avatar-${props.size}`]: props.size,
            'cm-avatar-icon': props.icon,
            'cm-avatar-img': props.src,
            'cm-avatar-square': props.shape === 'square'
        }));

        const onMutate = () => {
            string.style.Transform = '';
            string.style.webkitTransform = '';
            string.style.mozTransform = '';
            const wrapW = wrap.clientWidth;
            const strRect = string.getBoundingClientRect();
            const strW = strRect.width;
            const strH = 21;
            const theta = Math.acos(strH / wrapW);
            const w = Math.sin(theta) * wrapW;
            const ratio = strW > wrapW ? w / strW : 1;
            string.style.Transform = `scale(${ratio})`;
            string.style.webkitTransform = `scale(${ratio})`;
            string.style.mozTransform = `scale(${ratio})`;
        };

        let string: any;
        let wrap: any;
        let observer: MutationObserver | null;

        onMounted(() => {
            if (wrap && string) {
                onMutate();

                if (MutationObserver) {
                    observer = new MutationObserver(onMutate);
                    observer.observe(string, {
                        subtree: true,
                        childList: true,
                        characterData: true
                    });
                }

                onBeforeMount(() => {
                    if (observer) {
                        observer?.disconnect();
                        observer = null;
                    }
                });
            }
        });

        const style = computed(() => {
            const obj: any = {};
            if (typeof props.size === 'number') {
                obj.width = props.size + 'px';
                obj.height = props.size + 'px';
            }
            return obj;
        });

        const onMouseEnter = (e: any) => {
            hover.value = true;
            emit('mouseEnter', e);
        };

        const onMouseLeave = (e: any) => {
            hover.value = false;
            emit('mouseLeave', e);
        };

        return () => <span class={classList.value} style={style.value} onClick={(e) => {
            emit('click', e);
        }} ref={(el) => {
            wrap = el;
        }}
        onMouseenter={onMouseEnter} onMouseleave={onMouseLeave}>
            {
                hover.value
                    ? <div class="cm-avatar-hover">
                        {props.hoverMask || (slots.hoverMask && slots.hoverMask())}
                    </div>
                    : null
            }
            {
                props.src
                    ? <img class="cm-avatar-img" src={props.src} alt="" />
                    : props.icon ? props.icon :
                        <span class="cm-avatar-string" ref={(el) => {
                            string = el;
                        }}>{slots.default && slots.default()}</span>
            }
        </span>;
    },
});
